package message_api

import (
	"encoding/json"
	"github.com/gin-gonic/gin"
	"giv-vue-blog/global"
	"giv-vue-blog/models"
	"giv-vue-blog/models/res"
	"giv-vue-blog/utils/jwts"
	"strconv"
	"time"
)

type Message struct {
	SendUserID       uint      `json:"send_user_id"` //发送人id
	SendUserNickName string    `json:"send_user_nick_name"`
	SendUserAvatar   string    `json:"send_user_avatar"`
	RevUserID        uint      `json:"rev_user_id"` //接收人id
	RevUserNickName  string    `json:"rev_user_nick_name"`
	RevUserAvatar    string    `json:"rev_user_avatar"`
	Content          string    `json:"content"`       //消息内容
	CreatedAt        time.Time `json:"created_at"`    //创建时间
	MessageCount     int       `json:"message_count"` //消息条数
}
type RevMessageRequst struct {
	RevUserID uint `json:"rev_user_id" binding:"required"`
}

// MessageGroup 定义一个消息组  键: 由发送消息的用户id和接收消息的用户id组成，值: 这两者组成
type MessageGroup map[uint]*Message

// MessageListIDView 当是普通用户时，只显示我与对方的聊天记录 点击展开就是聊天记录
// @Summary 根据用户ID查看消息列表，普通用户只显示与对方的聊天记录
// @Tags 消息管理
// @Produce json
// @Param rev_user_id query uint true "接收人ID"
// @Success 200 {object} Message
// @Router /api/msg [get]
func (MessageApi) MessageListIDView(c *gin.Context) {
	_claims, _ := c.Get("claims")
	claims := _claims.(*jwts.CustomClaims)
	revUserID, _ := strconv.Atoi(c.Query("rev_user_id"))
	key := strconv.Itoa(int(claims.UserID)) + "_" + strconv.Itoa(revUserID)
	//values, err := global.Redis.LRange(key, 0, -1).Result()
	values, _ := global.Redis.Get(key).Result()
	//fmt.Println(values)
	if values == "" {
		// 如果 Redis 中的消息过期或不存在，则从数据库中查询并缓存到 Redis 中
		//对消息分组
		var messageGroup = MessageGroup{}
		//从数据库中找到用户发送的对应消息
		var msgList []models.MessageModel
		//将消息组保存到切片中
		var messages []Message
		//按最新时间排序消息
		global.DB.Order("created_at asc").
			Find(&msgList, "send_user_id =? or rev_user_id=?", claims.UserID, claims.UserID)
		for _, model := range msgList {
			//如何判断消息是一个组？-->当消息发送者和消息接收者的用户id加起来相等时 则这些消息就是一组消息
			message := Message{
				SendUserID:       model.SendUserID,
				SendUserNickName: model.SendUserNickName,
				SendUserAvatar:   model.SendUserAvatar,
				RevUserID:        model.RevUserID,
				RevUserNickName:  model.RevUserNickName,
				RevUserAvatar:    model.RevUserAvatar,
				Content:          model.Content,
				CreatedAt:        model.CreatedAt,
				MessageCount:     1,
			}
			//对接收者id和发送者id求和 通过map类型的键值检查 判断如果这个id和不在消息组，则对这个id和创建消息组
			//反之id和对应的消息组消息加1 并显示最新的消息(类似于qq、微信与别人聊天)
			idNum := model.SendUserID + model.RevUserID
			val, ok := messageGroup[idNum]
			//如果 ok 为 false，并且执行了 messageGroup[idNum] = &message 这行代码将当前聊天记录存储为新的聊天会话组，
			//并使用 continue 跳过下面的代码，那么整个循环并没有结束，它会继续处理下一条聊天记录。
			if !ok {
				//不存在消息组 将消息写进新的消息组里面
				messageGroup[idNum] = &message
				continue
			}
			//消息数量
			message.MessageCount = val.MessageCount + 1
			//将消息写到这个组里面
			messageGroup[idNum] = &message
		}
		//将消息组保存到切片中
		for _, message := range messageGroup {
			messages = append(messages, *message)
		}
		// 将消息列表存储到 Redis 中，并设置过期时间
		data, err := json.Marshal(messages)
		if err != nil {
			global.Log.Errorf("failed to marshal message list: %s", err.Error())
			res.FailedWithMsg("序列化消息保存到redis失败", c)
			return
		}
		//将消息的key及消息内容写到redis中
		err = global.Redis.Set(key, data, time.Hour*96).Err()
		if err != nil {
			global.Log.Errorf("failed to set message list to Redis: %s", err.Error())
			res.FailedWithMsg("消息保存到redis失败", c)
			return
		}
		res.OkWithData(messages, c)
		return
	} else {
		// 如果 Redis 中存在指定的 Key，则根据过期时间决定从 Redis 还是从数据库中读取
		// 解析 JSON 字符串
		var msg models.MessageModel
		err := json.Unmarshal([]byte(values), &msg)
		if err != nil {
			global.Log.Errorf("failed to unmarshal message list: %s", err.Error())
			res.FailedWithMsg("从redis反序列化读取消息失败", c)
			return
		}
		res.OkWithData(msg, c)
		return
	}
}
